/*
Automatic clinic tests using a robot arm.
Copyright (C) 2010  CIC-CPC, CHU Gabriel Montpied
All other trademarks, logos and copyrights are the property
of their respective owners.

This file is part of cpc-painbot.

cpc-painbot is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

cpc-painbot is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with cpc-painbot.  If not, see <http://www.gnu.org/licenses/>.
*/

#ifndef STIMULATEUR_H
#define STIMULATEUR_H

#include <QStateMachine>
#include <QTimer>

#include "zone.h"

#include "positionbras.h"

class Bras;
class Outil;

/*! Une façon de stimuler.
    Un Stimulateur représente une façon de stimuler, l'utilisation d'un outil pour effectuer une
    stimulation en une Zone donnée.
*/
class Stimulateur : public QStateMachine
{
Q_OBJECT

//! Bras utilisé par le Stimulateur.
Q_PROPERTY(Bras* bras READ bras WRITE setBras NOTIFY brasChange)

//! Position de la Stimulation.
Q_PROPERTY(PositionBras position READ position WRITE setPosition)

//! Outil courant utilisé pour la Stimulation.
Q_PROPERTY(Outil* outil READ outil WRITE setOutil)

//! Zone de Stimulation
Q_PROPERTY(Zone* zone READ zone WRITE setZone)

//! Durée de la Stimulation, en ms.
Q_PROPERTY(int duree READ duree WRITE setDuree)

//! Type du Stimulateur.
Q_PROPERTY(Type type READ type CONSTANT)

//! Types de Stimulateur.
Q_ENUMS(Type)
public:
    //! Les différents Types de Stimulateur.
    enum Type {
        VonFrey,
        Allodynie,
        PourTests
    };

    //! Nombre de Type existants.
    static const int nbTypes = 3;

    /*! Converti un Type en une chaîne.
        \param[in] type Le Type à afficher.
        \return La chaîne correspondante.
    */
    static QString typeToString(Type type);

    /*! Crée un Stimulateur à partir d'un Type.
        \param[in]  type    Type du Stimulateur à créer.
        \param      parent  Parent du Stimulateur.

        \retval 0               Le stimulateur n'a pu être créer.
        \retval Stimulateur*    Un Stimulateur du Type correspondant.
    */
    static Stimulateur *creer(Type type, QObject *parent = 0);


    /*! Bras utilisé.
        \return Le Bras utilisé pour la stimulation.
    */
    Bras *bras() const { return bras_; }

    /*! Position de la stimulation.
        \return L'emplacement de la stimulation.
    */
    PositionBras position() const { return position_; }

    /*! Zone de stimulation.
        \return La Zone où la Stimulation s'effectue.
    */
    Zone *zone() const { return zone_; }

    /*! Outil utilisé.
        Outil courant utilisé pour la Stimulation.
        \return L'Outil courant.
    */
    Outil *outil() const { return outil_; }

    /*! Durée d'une stimulation (ms)
        \return La durée d'une stimulation, en millisecondes.
    */
    int duree() const { return duree_->interval(); }

    /*! Type du Stimulateur.
        \return Le Type de ce Stimulateur.
    */
    Type type() const { return type_; }

signals:
    //! Emis lorsque le bras utilisé a changé.
    void brasChange(Bras *bras);

    //! Emis lorsque la durée de stimulation a changé.
    void dureeChangee(qint32 duree_ms);

public slots:
    /*! Définit le Bras à utiliser.
        \param bras Le Bras à utiliser.
    */
    void setBras(Bras *bras) { Q_ASSERT(bras != 0); bras_ = bras; refaireTransitions(); emit brasChange(bras_); }

    /*! Définit la position de stimulation.
        \param[in] position La position de stimulation.
    */
    void setPosition(const PositionBras &position) { position_ = position; }

    /*! Définit la Zone de Stimulation.
        \param zone Zone de stimulation.
    */
    void setZone(Zone *zone) { Q_ASSERT(zone != 0); zone_ = zone; }

    /*! Définit l'Outil.
        \param outil Outil de stimulation.
    */
    void setOutil(Outil *outil) { Q_ASSERT(outil != 0); outil_ = outil; }

    /*! Définit la durée d'une stimulation.
        \param[in] duree_ms Durée de la stimulation (en ms)
    */
    void setDuree(int duree_ms) { duree_->setInterval(duree_ms); }

    /*! Stimule à l'emplacement spécifié.
        Effectue une stimulation à l'emplacement donné.

        \param[in] position Emplacement où la stimulation doit se faire.
    */
    void stimuler(const PositionBras &position)
    { setPosition(position); stimuler(); }

    /*! Effectue une stimulation.
        Effectue une stimulation à la position donnée.
    */
    void stimuler() { zone_->positionLibre(position_); start(); }

protected:
    //! Constructeur.
    Stimulateur(Type type, QObject *parent = 0);

    virtual void refaireTransitions() = 0;

    Type type_; //!< Type de ce Stimulateur.
    Bras *bras_; //!< Bras utilisé.
    PositionBras position_; //!< Position de stimulation.
    Zone *zone_; //!< Zone de Stimulation.
    Outil *outil_; //!< Outil de Stimulation.
    QTimer *duree_; //!< Durée d'une Stimulation.
};

#endif // STIMULATEUR_H
